﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Minestorm.Evolved.Scenes;
using Microsoft.Xna.Framework.Graphics;
using Minestorm.Evolved.Assets;
using Microsoft.Xna.Framework;
using Minestorm.Evolved.GameLogic;

namespace Minestorm.Evolved.SceneObjects
{
    public class Earth : SceneObject
    {
        private Model _model;
        private PlanetEffect _effect;
        private Texture2D _texture;
        private Texture2D _textureBumpSpec;
        private Texture2D _textureClouds;
        private Matrix[] _boneTransforms;
        private BoundingSphere _boundingSphere;

        public override void LoadContent()
        {
            var content = ObjectFactory.InstanceOf<IAssetManager>();

            _model = content.Load(Models.Planet);
            _effect = content.Load(Effects.Planet);
            _texture = content.Load(Textures.Earth);
            _textureClouds = content.Load(Textures.Earth_Clouds);
            _textureBumpSpec = content.Load(Textures.Earth_BumpSpec);

            _effect.Projection = Scene.Camera.Projection;
            
            _boneTransforms = new Matrix[_model.Bones.Count];
            _model.CopyAbsoluteBoneTransformsTo(_boneTransforms);

            var radius = BoundingHelper.GetSphereRadius(_model);
            _boundingSphere = new BoundingSphere(Vector3.Zero, radius);

            base.LoadContent();
        }

        public override void UnloadContent()
        {
            _effect.Dispose();
            _texture.Dispose();
            _textureBumpSpec.Dispose();

            base.UnloadContent();
        }

        public override void Update(GameTime gameTime)
        {
            _planetRot += (float)gameTime.ElapsedGameTime.TotalMilliseconds * 0.00004f;
            _CloudRot += (float)gameTime.ElapsedGameTime.TotalMilliseconds * 0.00006f;

            base.Update(gameTime);
        }

        float _planetRot = 0f;
        float _CloudRot = 0f;

        private void DrawPlanet()
        {
            _effect.Texture = _texture;
            _effect.BumpSpecTexture = _textureBumpSpec;
            _effect.View = Scene.Camera.View;
            _effect.CameraPosition = Scene.Camera.Position;

            var world = Matrix.Identity * Matrix.CreateRotationY(_planetRot);

            _effect.SetTechnique(PlanetEffect.Technique.PlanetSurface);

            foreach (var mesh in _model.Meshes)
            {
                foreach (var part in mesh.MeshParts)
                    part.Effect = _effect;

                _effect.CameraPosition = Scene.Camera.Position;
                _effect.World = _boneTransforms[mesh.ParentBone.Index] * world;

                mesh.Draw();
            }
        }

        private void DrawClouds()
        {
            _effect.Texture = _textureClouds;
            _effect.BumpSpecTexture = null;
            _effect.View = Scene.Camera.View;
            _effect.CameraPosition = Scene.Camera.Position;

            var world = Matrix.Identity * Matrix.CreateScale(1.01f) * Matrix.CreateRotationY(_CloudRot);

            _effect.SetTechnique(PlanetEffect.Technique.Clouds);

            foreach (var mesh in _model.Meshes)
            {
                foreach (var part in mesh.MeshParts)
                    part.Effect = _effect;

                _effect.CameraPosition = Scene.Camera.Position;
                _effect.World = _boneTransforms[mesh.ParentBone.Index] * world;

                mesh.Draw();
            }
        }

        private void DrawGlow()
        {
            _effect.Texture = null;
            _effect.BumpSpecTexture = null;
            _effect.Color = Color.Blue;
            _effect.View = Scene.Camera.View;
            _effect.CameraPosition = Scene.Camera.Position;

            var world = Matrix.Identity * Matrix.CreateTranslation(0.08f, -0.08f, 0) * Matrix.CreateScale(1.1f);

            _effect.SetTechnique(PlanetEffect.Technique.Glow);

            SaveGraphicsState(GraphicsStates.DepthStencilState);

            GraphicsDevice.DepthStencilState = new DepthStencilState()
            {
                DepthBufferEnable = false
            };

            foreach (var mesh in _model.Meshes)
            {
                foreach (var part in mesh.MeshParts)
                    part.Effect = _effect;

                _effect.CameraPosition = Scene.Camera.Position;
                _effect.World = _boneTransforms[mesh.ParentBone.Index] * world;

                mesh.Draw();
            }

            RestoreGraphicsState();
        }

        public override void Draw(GameTime gameTime)
        {
            if (IsInViewFrustum(_boundingSphere))
            {
                DrawGlow();
                DrawPlanet();
                DrawClouds();
            }

            base.Draw(gameTime);
        }
    }
}
